package org.dftproject.genesis.data.genealogy.impl;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.dftproject.genesis.data.IAttribute;
import org.dftproject.genesis.data.IEntity;
import org.dftproject.genesis.data.genealogy.GenealogyConstants;
import org.dftproject.genesis.data.genealogy.GenealogyUtils;
import org.dftproject.genesis.data.genealogy.IName;
import org.dftproject.genesis.data.genealogy.IPerson;
import org.dftproject.genesis.data.genealogy.IRole;
import org.dftproject.genesis.data.genealogy.impl.internal.MergedSet;

public class MergedPerson implements IPerson {
	
	// TODO cache merged sets of data
	
	private final Set<IPerson> constituents = Collections.synchronizedSet(new HashSet<IPerson>());
	
	public MergedPerson() {
	}
	
	public MergedPerson(IPerson constituent) {
		addConstituent(constituent);
	}
	
	public MergedPerson(Set<IPerson> constituents) {
		for (IPerson constituent : constituents)
			addConstituent(constituent);
	}
	
	public void addConstituent(IPerson constituent) {
		constituents.add(constituent);
		List<Object> persons = GenealogyUtils.getValues(constituent, GenealogyConstants.sameAs, IPerson.class);
		for (Object person : persons)
			constituents.add((IPerson) person);
	}

	public Set<IRole> getRoles() {
		MergedSet<IRole> roles = new MergedSet<IRole>();
		for (IPerson constituent : constituents)
			roles.addSet(constituent.getRoles());
		return roles;
	}

	public Set<IRole> getRoles(String[] types) {
		MergedSet<IRole> roles = new MergedSet<IRole>();
		for (IPerson constituent : constituents)
			roles.addSet(constituent.getRoles(types));
		return roles;
	}

	public Set<IRole> getRoles(String type) {
		MergedSet<IRole> roles = new MergedSet<IRole>();
		for (IPerson constituent : constituents)
			roles.addSet(constituent.getRoles(type));
		return roles;
	}

	public Set<IAttribute> getAttributes() {
		MergedSet<IAttribute> attributes = new MergedSet<IAttribute>();
		for (IPerson constituent : constituents)
			attributes.addSet(constituent.getAttributes());
		return attributes;
	}

	public Set<IAttribute> getAttributes(String name) {
		MergedSet<IAttribute> attributes = new MergedSet<IAttribute>();
		for (IPerson constituent : constituents)
			attributes.addSet(constituent.getAttributes(name));
		return attributes;
	}
	
	@Override
	public String toString() {
		IName name = GenealogyUtils.getName(this);
		if (name != null)
			return "MergedPerson(" + GenealogyUtils.stringFromName(name) + ")";
		return super.toString();
	}

	public Set<IEntity> getEntities() {
		Set<IEntity> entities = new HashSet<IEntity>();
		entities.addAll(constituents);
		return entities;
	}

	public boolean sameAs(IEntity other) {
		Set<IEntity> intersection = new HashSet<IEntity>(other.getEntities());
        intersection.retainAll(constituents);
        return !intersection.isEmpty();
	}

}
